package org.openkanban.server.controller;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.dozer.DozerBeanMapper;
import org.openkanban.server.domain.User;
import org.openkanban.server.interceptor.annotation.SecurityInterception;
import org.openkanban.server.service.UserService;
import org.openkanban.server.session.SessionAttributeHelper;
import org.openkanban.server.util.MultipartUtil;
import org.openkanban.shared.dto.StatusDto;
import org.openkanban.shared.dto.UserDto;
import org.openkanban.shared.util.StatusCodes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * Controller that is responsible for all user requests. Calls corresponding
 * services to proceed.
 */
@Controller
@RequestMapping(value = "/user")
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private SessionAttributeHelper sessionAttributes;

    @Autowired
    private DozerBeanMapper mapper;

    @RequestMapping(method = RequestMethod.POST, value = "/signup")
    @ResponseBody
    public void createUser(UserDto userDto, HttpServletRequest req, HttpServletResponse resp) {
	User user = MultipartUtil.processFiles(req, resp);
	userService.signUp(user);
    }

    @RequestMapping(method = RequestMethod.POST, value = "/login")
    @ResponseBody
    public UserDto loginUser(User user, HttpServletRequest req, HttpServletResponse resp) {
	// if login is valid then userId is set by the userService
	boolean logInSucessfull = userService.logIn(user);

	if (logInSucessfull) {
	    req.getSession().setAttribute("userId", user.getUserId());

	    user = userService.getUser(user.getUserId());
	    UserDto userDto = mapper.map(user, UserDto.class);
	    return userDto;
	} else {
	    resp.setStatus(401);
	    return null;
	}
    }

    @RequestMapping(method = RequestMethod.POST, value = "/logout")
    @ResponseBody
    public String logoutUser(HttpServletRequest req, HttpServletResponse resp) {
	req.getSession().invalidate();
	return "success=true";
    }

    @RequestMapping(method = RequestMethod.POST, value = "/account")
    @ResponseBody
    @SecurityInterception
    public UserDto get(HttpServletRequest req, HttpServletResponse resp) {
	User user = userService.getUser(sessionAttributes.getUserId(req));
	return mapper.map(user, UserDto.class);
    }

    @RequestMapping(method = RequestMethod.GET, value = "/contact/get")
    @ResponseBody
    @SecurityInterception
    public UserDto[] getContacts(HttpServletRequest req, HttpServletResponse resp) {
	User requestedUser = userService.getUser(sessionAttributes.getUserId(req));
	List<User> contactsArray = requestedUser.getKontakteEmailList();

	List<UserDto> userDtoList = new ArrayList<UserDto>();
	for (User user : contactsArray) {
	    userDtoList.add(mapper.map(user, UserDto.class));
	}

	return userDtoList.toArray(new UserDto[] {});

    }

    @RequestMapping(method = RequestMethod.POST, value = "/contact/add")
    @ResponseBody
    @SecurityInterception
    public StatusDto addContact(String parentUserId, String contactMail, HttpServletRequest req, HttpServletResponse resp) {
	StatusCodes status = userService.addContact(parentUserId, contactMail);
	return new StatusDto(status.getStatusCode(), status.getStatusText());
    }

    @RequestMapping(method = RequestMethod.POST, value = "/contact/remove")
    @ResponseBody
    @SecurityInterception
    public StatusDto removeContact(String contactMail, HttpServletRequest req, HttpServletResponse resp) {
	User user = userService.getUser(sessionAttributes.getUserId(req));
	StatusCodes status = userService.removeContact(user, contactMail);
	return new StatusDto(status.getStatusCode(), status.getStatusText());
    }

    @RequestMapping(method = RequestMethod.POST, value = "/update/account")
    @ResponseBody
    @SecurityInterception
    public StatusDto updateAccount(UserDto userDto, HttpServletRequest req, HttpServletResponse resp) {
	User user = mapper.map(userDto, User.class);
	user.setUserId(sessionAttributes.getUserId(req));
	StatusCodes status = userService.updateUser(user);
	return new StatusDto(status.getStatusCode(), status.getStatusText());
    }

    @RequestMapping(method = RequestMethod.POST, value = "/update/password")
    @ResponseBody
    @SecurityInterception
    public StatusDto updatePassword(String oldPassword, String newPassword, HttpServletRequest req, HttpServletResponse resp) {
	StatusCodes status = userService.updatePassword(sessionAttributes.getUserId(req), oldPassword, newPassword);
	return new StatusDto(status.getStatusCode(), status.getStatusText());
    }

    @RequestMapping(method = RequestMethod.POST, value = "/update/avatar")
    @ResponseBody
    @SecurityInterception
    public StatusDto updateAvatar(HttpServletRequest req, HttpServletResponse resp) {
	User user = userService.getUser(sessionAttributes.getUserId(req));
	if (avatarDoesNotExist(user)) {
	    User multipartUser = MultipartUtil.processFiles(req, resp);
	    userService.updateAvatar(sessionAttributes.getUserId(req), multipartUser.getAvatarUrl());
	} else {
	    MultipartUtil.processFiles(user.getAvatarUrl().replaceAll("\\..*", ""), req, resp);
	}
	return new StatusDto(StatusCodes.OK.getStatusCode(), StatusCodes.OK.getStatusText());
    }

    private boolean avatarDoesNotExist(User user) {
	final String DEFAULT_AVATAR_PNG = "default.png";
	return DEFAULT_AVATAR_PNG.equals(user.getAvatarUrl()) || StringUtils.isEmpty(user.getAvatarUrl());
    }

    public UserService getUserService() {
	return userService;
    }

    public void setUserService(UserService userService) {
	this.userService = userService;
    }

    public void setSessionAttributes(SessionAttributeHelper sessionAttributes) {
	this.sessionAttributes = sessionAttributes;
    }

    public void setMapper(DozerBeanMapper mapper) {
	this.mapper = mapper;
    }

}
